package edu.yonsei.iwb.smarttv.model;

import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import edu.yonsei.iwb.smarttv.model.measure.PropertyWeight;
import edu.yonsei.iwb.smarttv.model.measure.PropertyWeightSet;
import edu.yonsei.iwb.smarttv.model.measure.WeightModel;
import java.util.Vector;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Hashtable;

/**
 * 노드들의 웨이트를 저장하기 위한 배열.
 * 
 * @author Joo
 */
public class MatrixModel {

    private Model model;
    private Vector<MNode> nodeSet;    
    private Hashtable<Resource, Integer> nodeidTable;
    private MArcSet [][] arcMatrix;
    private double[][] weightInfo;


    public MatrixModel() {        
        this.nodeSet = new Vector<MNode>();
        this.nodeidTable = new Hashtable<Resource, Integer>();
    }

    public Vector<MNode> getNodeSet() {
        return nodeSet;
    }

    public Hashtable<Resource, Integer> getNodeIDTable() {
        return nodeidTable;
    }
    
    public double[][] getWeightInfo(){
        return this.weightInfo;
    }
    
    
    public MArcSet[][] getArcMatrix(){
        return this.arcMatrix;
    }
    
    private boolean isObjectProperty(Resource property) {
        StmtIterator checkObjectProperty = model.listStatements(property, RDF.type, OWL.ObjectProperty);
        return checkObjectProperty.hasNext();
    }

    private boolean isClass(Resource subject) {
        StmtIterator isClass = model.listStatements(subject, RDF.type, OWL.Class);
        return isClass.hasNext();
    }

    public void initializeGraph(Model model, WeightModel weightModel) {
        this.model = model;
//        model.write(System.out, "N-TRIPLE");
        int idOfNode = 0;
        // 모든 클래스를 가져온다.
        ResIterator classList = model.listSubjectsWithProperty(RDF.type, OWL.Class);
        
        Property isDummy = model.getProperty("http://iweb.yonsei.ac.kr/ontologies/smarttv/isDummy");
        Literal valueTrue = model.createTypedLiteral("true", "http://www.w3.org/2001/XMLSchema#boolean");
        
        while (classList.hasNext()) {
            Resource singleClass = classList.nextResource();
            if (!singleClass.isURIResource()) {
                continue;
            } 
            // 가져온 클래스에 id를 순서대로 부여한다.
            StmtIterator sm = model.listStatements(singleClass, isDummy, valueTrue);
            MNode n;
            if(sm.hasNext()) {
                n = new MNode(singleClass, idOfNode, NodeType.CLASS_TYPE, true);
            } else {
                n = new MNode(singleClass, idOfNode, NodeType.CLASS_TYPE, false);  
            }
            nodeSet.add(n);
            
            // 노드들을 검색할 수 있도록 nodeInfo에 저장한다.
            nodeidTable.put(n.getNode(), n.getId());            
            idOfNode++;
        }
  
        this.initializeWeightMatrixValue();        
                
        Hashtable<Property, PropertyWeightSet> weightTable = weightModel.getTripleWeightTable();
        
        Enumeration<Property> keys = weightTable.keys();
        while(keys.hasMoreElements()){
            Property p = keys.nextElement();
            PropertyWeightSet pws = weightTable.get(p);
            
            for (int i = 0; i < pws.size(); i++) {
                PropertyWeight pw = pws.get(i);
                
                Resource dr = pw.getDomain();
                Resource rr = pw.getRange();
                
                int domain_id = nodeidTable.get(dr);
                int range_id = nodeidTable.get(rr);
                
                
                MArc arc = new MArc(nodeSet.get(domain_id), nodeSet.get(range_id), pw.getProperty(), pw.getWeight(), true);
                MArcSet marcset1 = this.arcMatrix[domain_id][range_id];
                marcset1.add(arc);
                
                MArc arc2 = new MArc(nodeSet.get(domain_id), nodeSet.get(range_id), pw.getProperty(), pw.getWeight(), false);
                MArcSet marcset2 = this.arcMatrix[range_id][domain_id]; // 양 방향으로 다 넣어주는가?
                marcset2.add(arc2);                
            }
        }

    }
    

    private void initializeWeightMatrixValue() {
        this.arcMatrix = new MArcSet[nodeSet.size()][nodeSet.size()];                
        
        for (int i = 0; i < nodeSet.size(); i++) {
            for(int j = 0; j < nodeSet.size(); j++) {
                arcMatrix[i][j] = new MArcSet();
            }
        }        
        
        this.weightInfo = new double[nodeSet.size()][nodeSet.size()];
        Arrays.fill(weightInfo[nodeSet.size()-1], 99);
        for (int i = 0; i < nodeSet.size()-1; i++) {
            Arrays.fill(weightInfo[i], Double.POSITIVE_INFINITY);
        }        
        
    }
    
}
